/*
 * Keyboard Driver
*/

#include "kb.h"
#include "video.h"
#include "util.h"
#include "isr.h"

static unsigned int controlBits;

extern console_t vcs[];
extern console_t *curr_vc;

// scancode table - unshifted
unsigned char kbdus[128] = 
{
	0, 27, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b', '\t', 
	'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', 0 /* ctrl */, 'a', 's', 
	'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', 0 /* left shift */, '\\', 'z', 'x', 'c', 'v', 
	'b', 'n', 'm', ',', '.', '/', 0, /* right shift */ '*', 0, /* alt */ ' ', /* spacebar */ 0, /* caps lock */ 0, /* f1 */
	0, 0, 0, 0, 0, 0, 0, 0,
	0, // ... F10
	0, // scroll lock
	0, // home
	0, // up arrow
	0, // page up
	0, 
	'-', 0, 0, 0, '+',
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0
};

// scancode table - shifted
unsigned char kbdus_shift[128] = 
{
	0, 27, '!', '@', '#', '$', '%', '^', '&', '*',
	'(', ')', '_', '+', '\b', '\t', 'Q', 'W', 'E', 'R',
	'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n',
	0, /* 29 - control */  'A', 'S', 'D', 'F', 'G', 'H', 
	'J', 'K', 'L', ':',
	'\"', '~', 0 /* left shift */,
	'|', 'Z', 'X', 'C', 'V', 'B', 'N',
	'M', '<', '>', '?', 0, /* right shift */
	'*',
	0, /* alt */
	' ', // spacebar
	0, // caps lock
	0, // f1 key
	0, 0, 0, 0, 0, 0, 0, 0,
	0, // ... F10
	0, // scroll lock
	0, // home
	0, // up arrow
	0, // page up
	0, 
	'-', 0, 0, 0, '+',
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	0
};

// handles the keyboard interrupt
void keyboard_handler(regs *r)
{
	unsigned char scancode, ch;
	
	// read from the keyboard's data buffer
	scancode = inportb(0x60);
	
	//*curr_vc->keystrokes.data = scancode;
	
	switch(scancode)
	{
		case LEFT_SHIFT:
		case RIGHT_SHIFT:
			controlBits |= SHIFT;
			break;
		case (LEFT_SHIFT | 0x80):
		case (RIGHT_SHIFT | 0x80):
			controlBits &= ~SHIFT;
			break;
		case LEFT_ALT:
			controlBits |= ALT;
			break;
		case (LEFT_ALT | 0x80):
			controlBits &= ~ALT;
		case LEFT_CTRL:
			controlBits |= CTRL;
			break;
		case (LEFT_CTRL | 0x80):
			controlBits &= ~CTRL;
			break;
		case F1:
			switchConsole(0);
			break;
		case F2:
			switchConsole(1);
			break;
		case F3:
			switchConsole(2);
			break;
		case F4:
			switchConsole(3);
			break;
		case F5:
			switchConsole(4);
			break;
		case F6:
			switchConsole(5);
			break;
		case BACKSPACE:
			puts("\b \b");
			break;
		case DELETE: // three-finger salute !
			if((controlBits & CTRL) && (controlBits & ALT))
			{
				disable();
				reboot();
			}
			break;
		case UP:
			move_up();
			break;
		case LEFT:
			move_left();
			break;
		case RIGHT:
			move_right();
			break;
		case DOWN:
			move_down();
			break;
		default: 
			if(!(scancode & 0x80)) // a key was pushed down
			{
				ch = ((controlBits & SHIFT) ? kbdus_shift : kbdus)[scancode];
				//putch(ch);
				curr_vc->keystrokes.data[0] = ch;
			}
			break;
	}
	outportb(0x20, 0x20);
}

// installs the keyboard handler
void keyboardInstall()
{
	static unsigned char buffers[KBD_BUF * NUM_VC];
	register_interrupt_handler(IRQ1, &keyboard_handler);
	controlBits = 0x00;
	unsigned int i;
	
	for(i = 0; i < NUM_VC; i++)
	{
		vcs[i].keystrokes.data = buffers + KBD_BUF;
		vcs[i].keystrokes.size = KBD_BUF;
	}
	for(i = 0; i < KBD_BUF * NUM_VC; i++)
		buffers[i] = 0;
}

